package cz.matasek.dbLogger.database;

import cz.matasek.dbLogger.LoggingAvailability;
import cz.matasek.dbLogger.exception.NoConnectionEstablishedException;
import cz.matasek.dbLogger.model.DateTime;
import cz.matasek.dbLogger.model.TriggeringEvents;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.Map;

/**
 * The interface providing connection to a database.
 *
 * @author Luboš Matásek
 */
public interface DatabaseConnection {

    /**
     * Returns currently established connection to the database.
     *
     * @return the {@link java.sql.Connection} object, representing a connection
     * to the database
     */
    public Connection getConnection();

    /**
     * Returns database platform, this class is connected to.
     *
     * @return database platform
     */
    public DatabasePlatform getPlatform();

    /**
     * Returns name of the database platform, this class is connected to.
     *
     * @return name of the database platform
     */
    public String getPlatformName();

    /**
     * Returns logging availability.
     *
     * @return the {@link cz.matasek.dbLogger.LoggingAvailability} object
     */
    public LoggingAvailability getLoggingAvailability();

    /**
     * Returns logging objects prefix.
     *
     * @return logging objects prefix
     */
    public String getLoggingObjectsPrefix();

    /**
     * Returns database description.
     *
     * @return database description
     */
    public String getDatabaseDescription();

    /**
     * Returns this database JDBC driver class name.
     *
     * @return database JDBC driver class name
     */
    public String getJdbcDriverName();

    /**
     * Connects to the database.
     * Also reads database metadata.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.JdbcDriverMissingException}
     * if JDBC driver is missing.
     *
     * @throws cz.matasek.dbLogger.exception.NoConnectionEstablishedException
     * if database access error occurs
     */
    public void connect() throws NoConnectionEstablishedException;

    /**
     * Disconnects from the database.
     * Also clears database metadata.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     */
    public void disconnect();

    /**
     * Creates environment for logging.
     * Prefix function and logging sequence are created.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param prefix prefix of logging objects
     */
    public void createLoggingEnvironment(String prefix);

    /**
     * Drops environment for logging.
     * Prefix function and logging sequence are dropped.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param cascaded <code>true</code> if all dependent objects will be dropped
     */
    public void dropLoggingEnvironment(boolean cascaded);

    /**
     * Retrieves whether specified function exists in the database.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param functionName name of the function
     * @return true if prefix function exists; false otherwise
     */
    public boolean hasFunction(String functionName);

    /**
     * Retrieves whether the specified sequence exists in the database.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param sequenceName name of the sequence
     * @return true if the sequence exists in the database; false otherwise
     */
    public boolean hasSequence(String sequenceName);

    /**
     * Retrieves whether the database has the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName searched table
     * @return true if the database has the table; false otherwise
     */
    public boolean hasTable(String tableName);

    /**
     * Retrieves whether the specified trigger exists in the database.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param triggerName the trigger name
     * @return true if the trigger exists; false otherwise
     */
    public boolean hasTrigger(String triggerName);

    /**
     * Retrieves whether the specified table has column with the given name.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName name of the table
     * @param columnName name of the column
     * @return true if the column exists in the table; false otherwise
     */
    public boolean hasColumn(String tableName, String columnName);

    /**
     * Returns logging table name for this database.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     *
     * @return logging table name
     */
    public String getLoggingTableName();

    /**
     * Retrieves whether the database has the logging table.
     *
     * @return true if the logging table exists; false otherwise
     */
    public boolean hasLoggingTable();

    /**
     * Creates logging table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     * Can throw {@link cz.matasek.dbLogger.exception.ObjectAlreadyExistsException}
     * if logging table already exists.
     */
    public void createLoggingTable();

    /**
     * Drops logging table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     * Can throw {@link cz.matasek.dbLogger.exception.ObjectDoesNotExistException}
     * if logging table does not exist.
     */
    public void dropLoggingTable();

    /**
     * Return set of tables in the database already read by readMetadata
     * function.
     *
     * @return set of tables in the database
     */
    public Collection<String> getTables();

    /**
     * Return set of users in the database already read by readMetadata
     * function.
     *
     * @return set of users in the database
     */
    public Collection<String> getUsers();

    /**
     * Creates logging trigger for specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     * Can throw {@link cz.matasek.dbLogger.exception.ObjectDoesNotExistException}
     * if logging table does not exist.
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName table to be logged
     * @param events events to be logged
     * @param loggedColumnNames the collection of column names to be logged
     */
    public void createLoggingTrigger(String tableName, TriggeringEvents events,
            Collection<String> loggedColumnNames);

    /**
     * Drops logging trigger for specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     * Can throw {@link cz.matasek.dbLogger.exception.ObjectDoesNotExistException}
     * if logging trigger does not exist.
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName table, whose trigger will be deleted
     */
    public void dropLoggingTrigger(String tableName);

    /**
     * Retrieves whether the specified table has logging trigger.
     *
     * @param tableName name of the table
     * @return true if the table has the logging trigger; false otherwise
     */
    public boolean hasLoggingTrigger(String tableName);

    /**
     * Returns names of the history columns.
     *
     * @return names of the history columns
     */
    public String[] getHistoryColumnsNames();

    /**
     * Returns name of the history table for the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.LoggingUnavailableException}
     * if logging is inactive in the database.
     *
     * @param tableName the table name
     * @return history table name
     */
    public String getHistoryTableName(String tableName);

    /**
     * Starts logging full history in the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName table to be logged
     */
    public void startLoggingHistory(String tableName);

    /**
     * Ends logging full history in the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName table to be logged
     */
    public void stopLoggingHistory(String tableName);

    /**
     * Returns columns for the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName name of the table
     * @return mapping of column names to column types in the table
     */
    public Map<String, String> getColumns(String tableName);

    /**
     * Returns non-logging columns for the specified table.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName name of the table
     * @return mapping of column names to column types in the table
     */
    public Map<String, String> getNonLoggingColumns(String tableName);

    /**
     * Returns columns, which values are currently logged.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @param tableName name of the table
     * @return list of logged columns in the table
     */
    public Collection<String> getLoggedColumns(String tableName);

    /**
     * Returns prefix for the database.
     *
     * Can throw {@link cz.matasek.dbLogger.exception.ObjectDoesNotExistException}
     * if prefix function does not exist.
     * Can throw {@link cz.matasek.dbLogger.exception.DatabaseErrorException}
     * if database error occurs.
     *
     * @return prefix for this application objects
     */
    public String getPrefix();

    /**
     * Retrieves whether the specified table has the history table.
     *
     * @param tableName the table name
     * @return true if the table has history table; false
     * otherwise
     */
    public boolean hasHistoryTable(String tableName);

    /**
     * Returns all rows in the table present in the specified date.
     *
     * @param tableName name of the table
     * @param dateTime given date
     * @return content of the table in specified date
     */
    public ResultSet getHistoricalTableContent(String tableName, DateTime dateTime);

    /**
     * Returns trigger events in the specified table.
     *
     * @param tableName name of the table
     * @return trigger events
     */
    public TriggeringEvents getTriggerEvents(String tableName);

    /**
     * Returns if this database supports on update triggers.
     *
     * @return true, if on update triggers are supported; false otherwise
     */
    public boolean supportOnUpdateTriggers();

    /**
     * Returns rows from the logging table that have met the specified requirements.
     *
     * @param tableNames required tables
     * @param operations required operations
     * @param userNames required users
     * @param dateTimeFrom required starting date and time
     * @param dateTimeTo required final date and time
     * @return rows from the logging table
     */
    public ResultSet getLoggingTableContent(Object[] tableNames, Object[] operations, Object[] userNames,
            DateTime dateTimeFrom, DateTime dateTimeTo);

    /**
     * Returns collection of objects created by the logging application.
     *
     * @return mapping of logging object names to their types
     */
    public Map<String, DatabaseObjectType> getLoggingObjects();
}
